
/*-------------------------------------------------------------------------*/
/**
   @file    iniparser.c
   @author  N. Devillard
   @brief   Parser for ini files.
*/
/*--------------------------------------------------------------------------*/
/*---------------------------- Includes ------------------------------------*/
#include <ctype.h>
#include "iniparser.h"

/*---------------------------- Defines -------------------------------------*/
#define ASCIILINESZ         (1024)
#define INI_INVALID_KEY     ((char *)-1)

/*---------------------------------------------------------------------------
 * Private to this module
 ---------------------------------------------------------------------------*/
/**
 * This enum stores the status for each parsed line (internal use only).
 */
typedef enum _line_status_ {
	LINE_UNPROCESSED,
	LINE_ERROR,
	LINE_EMPTY,
	LINE_COMMENT,
	LINE_SECTION,
	LINE_VALUE
} line_status;

/*-------------------------------------------------------------------------*/
/**
  @brief    Convert a string to lowercase.
  @param    s   String to convert.

  This function modifies the string passed, the modified string
  contains a lowercased version of the input string.
 */
/*--------------------------------------------------------------------------*/
#if 0
static void strlwc(char *s)
{
	int i;

	if (s == NULL) return;
	i = 0;
	while (s[i]) {
		s[i] = (char)tolower((int)s[i]);
		i++;
	}
}
#endif
/*-------------------------------------------------------------------------*/
/**
  @brief    Remove blanks at the beginning and the end of a string.
  @param    s   String to parse.

  This function modifies the input string and returns a modified string
  which is identical to the input string, except that all blank
  characters at the end and the beg. of the string have been removed.
 */
/*--------------------------------------------------------------------------*/
static void strstrip(char *s)
{
	if (s == NULL)
		return;

	char *last = s + strlen(s);
	char *dest = s;

	while (isspace((int)*s) && *s)
		s++;

	while (last > s) {
		if (!isspace((int)*(last-1)))
			break;
		last--;
	}
	*last = (char)0;

	memmove(dest, s, last - s + 1);
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get number of sections in a dictionary
  @param    d   Dictionary to examine
  @return   int Number of sections found in dictionary

  This function returns the number of sections found in a dictionary.
  The test to recognize sections is done on the string stored in the
  dictionary: a section name is given as "section" whereas a key is
  stored as "section:key", thus the test looks for entries that do not
  contain a colon.

  This clearly fails in the case a section name contains a colon, but
  this should simply be avoided.

  This function returns -1 in case of error.
 */
/*--------------------------------------------------------------------------*/
int iniparser_getnsec(dictionary *d)
{
	int i;
	int nsec;

	if (d == NULL)
		return -1;
	nsec = 0;
	for (i = 0; i < d->size; i++) {
		if (d->key[i] == NULL)
			continue;
		if (strchr(d->key[i], ':') == NULL) {
			nsec++;
		}
	}
	return nsec;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get name for section n in a dictionary.
  @param    d   Dictionary to examine
  @param    n   Section number (from 0 to nsec-1).
  @return   Pointer to char string

  This function locates the n-th section in a dictionary and returns
  its name as a pointer to a string statically allocated inside the
  dictionary. Do not free or modify the returned string!

  This function returns NULL in case of error.
 */
/*--------------------------------------------------------------------------*/
char *iniparser_getsecname(dictionary *d, int n)
{
	int i;
	int foundsec;

	if (d == NULL || n < 0)
		return NULL;
	foundsec = 0;
	for (i = 0; i < d->size; i++) {
		if (d->key[i] == NULL)
			continue;
		if (strchr(d->key[i], ':') == NULL) {
			foundsec++;
			if (foundsec > n)
				break;
		}
	}
	if (foundsec <= n) {
		return NULL;
	}
	return d->key[i];
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Dump a dictionary to an opened file pointer.
  @param    d   Dictionary to dump.
  @param    f   Opened file pointer to dump to.
  @return   void

  This function prints out the contents of a dictionary, one element by
  line, onto the provided file pointer. It is OK to specify @c stderr
  or @c stdout as output files. This function is meant for debugging
  purposes mostly.
 */
/*--------------------------------------------------------------------------*/
void iniparser_dump(dictionary *d, FILE *f)
{
	int     i;

	if (d == NULL || f == NULL)
		return;
	for (i = 0; i < d->size; i++) {
		if (d->key[i] == NULL)
			continue;
		if (d->val[i] != NULL) {
			fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
		} else {
			fprintf(f, "[%s]=UNDEF\n", d->key[i]);
		}
	}
	return;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Save a dictionary to a loadable ini file
  @param    d   Dictionary to dump
  @param    f   Opened file pointer to dump to
  @return   void

  This function dumps a given dictionary into a loadable ini file.
  It is Ok to specify @c stderr or @c stdout as output files.
 */
/*--------------------------------------------------------------------------*/
void iniparser_dump_ini(dictionary *d, FILE *f)
{
	int     i;
	int     nsec;
	char    *secname;

	if (d == NULL || f == NULL)
		return;

	nsec = iniparser_getnsec(d);
	if (nsec < 1) {
		/* No section in file: dump all keys as they are */
		for (i = 0; i < d->size; i++) {
			if (d->key[i] == NULL)
				continue;
			fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
		}
		return;
	}
	for (i = 0; i < nsec; i++) {
		secname = iniparser_getsecname(d, i);
		iniparser_dumpsection_ini(d, secname, f);
	}
	fprintf(f, "\n");
	return;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Save a dictionary section to a loadable ini file
  @param    d   Dictionary to dump
  @param    s   Section name of dictionary to dump
  @param    f   Opened file pointer to dump to
  @return   void

  This function dumps a given section of a given dictionary into a loadable ini
  file.  It is Ok to specify @c stderr or @c stdout as output files.
 */
/*--------------------------------------------------------------------------*/
void iniparser_dumpsection_ini(dictionary *d, char *s, FILE *f)
{
	int     j;
	char    *keym;
	int     secsize;

	if (d == NULL || f == NULL)
		return;
	if (!iniparser_find_entry(d, s))
		return;

	fprintf(f, "\n[%s]\n", s);
	secsize = (int)strlen(s) + 2;
	keym = malloc(secsize);
	snprintf(keym, secsize, "%s:", s);
	for (j = 0; j < d->size; j++) {
		if (d->key[j] == NULL)
			continue;
		if (!strncmp(d->key[j], keym, secsize-1)) {
			fprintf(f,
					"%-30s = %s\n",
					d->key[j]+secsize-1,
					d->val[j] ? d->val[j] : "");
		}
	}
	fprintf(f, "\n");
	free(keym);
	return;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get the number of keys in a section of a dictionary.
  @param    d   Dictionary to examine
  @param    s   Section name of dictionary to examine
  @return   Number of keys in section
 */
/*--------------------------------------------------------------------------*/
int iniparser_getsecnkeys(dictionary *d, char *s)
{
	int     secsize, nkeys;
	char    *keym;
	int	j;

	nkeys = 0;

	if (d == NULL)
		return nkeys;
	if (!iniparser_find_entry(d, s))
		return nkeys;

	secsize = (int)strlen(s)+2;
	keym = malloc(secsize);
	snprintf(keym, secsize, "%s:", s);

	for (j = 0; j < d->size; j++) {
		if (d->key[j] == NULL)
			continue;
		if (!strncmp(d->key[j], keym, secsize-1))
			nkeys++;
	}
	free(keym);
	return nkeys;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get the number of keys in a section of a dictionary.
  @param    d   Dictionary to examine
  @param    s   Section name of dictionary to examine
  @return   pointer to statically allocated character strings

  This function queries a dictionary and finds all keys in a given section.
  Each pointer in the returned char pointer-to-pointer is pointing to
  a string allocated in the dictionary; do not free or modify them.

  This function returns NULL in case of error.
 */
/*--------------------------------------------------------------------------*/
char **iniparser_getseckeys(dictionary *d, char *s)
{

	char	**keys;
	int	i, j;
	char    *keym;
	int     secsize, nkeys;

	keys = NULL;

	if (d == NULL)
		return keys;
	if (!iniparser_find_entry(d, s))
		return keys;

	nkeys = iniparser_getsecnkeys(d, s);

	keys = (char **) malloc(nkeys*sizeof(char *));

	secsize  = (int)strlen(s) + 2;
	keym = malloc(secsize);
	snprintf(keym, secsize, "%s:", s);

	i = 0;

	for (j = 0; j < d->size; j++) {
		if (d->key[j] == NULL)
			continue;
		if (!strncmp(d->key[j], keym, secsize-1)) {
			keys[i] = d->key[j];
			i++;
		}
	}
	free(keym);
	return keys;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key
  @param    d       Dictionary to search
  @param    key     Key string to look for
  @param    def     Default value to return if key not found.
  @return   pointer to statically allocated character string

  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the pointer passed as 'def' is returned.
  The returned char pointer is pointing to a string allocated in
  the dictionary, do not free or modify it.
 */
/*--------------------------------------------------------------------------*/
char *iniparser_getstring(dictionary *d, const char *key, char *def)
{
	char *lc_key;
	char *sval;

	if (d == NULL || key == NULL)
		return def;

	lc_key = aw_strdup(key);
	//strlwc(lc_key);
	sval = dictionary_get(d, lc_key, def);
	free(lc_key);
	return sval;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key, convert to an int
  @param    d Dictionary to search
  @param    key Key string to look for
  @param    notfound Value to return in case of error
  @return   integer

  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the notfound value is returned.

  Supported values for integers include the usual C notation
  so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
  are supported. Examples:

  "42"      ->  42
  "042"     ->  34 (octal -> decimal)
  "0x42"    ->  66 (hexa  -> decimal)

  Warning: the conversion may overflow in various ways. Conversion is
  totally outsourced to strtol(), see the associated man page for overflow
  handling.

  Credits: Thanks to A. Becker for suggesting strtol()
 */
/*--------------------------------------------------------------------------*/
int iniparser_getint(dictionary *d, const char *key, int notfound)
{
	char    *str;
	str = iniparser_getstring(d, key, INI_INVALID_KEY);
	if (str == INI_INVALID_KEY)
		return notfound;
	return (int)strtol(str, NULL, 0);
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key, convert to a double
  @param    d Dictionary to search
  @param    key Key string to look for
  @param    notfound Value to return in case of error
  @return   double

  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the notfound value is returned.
 */
/*--------------------------------------------------------------------------*/
double iniparser_getdouble(dictionary *d, const char *key, double notfound)
{
	char    *str;

	str = iniparser_getstring(d, key, INI_INVALID_KEY);
	if (str == INI_INVALID_KEY)
		return notfound;
	return atof(str);
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Get the string associated to a key, convert to a boolean
  @param    d Dictionary to search
  @param    key Key string to look for
  @param    notfound Value to return in case of error
  @return   integer

  This function queries a dictionary for a key. A key as read from an
  ini file is given as "section:key". If the key cannot be found,
  the notfound value is returned.

  A true boolean is found if one of the following is matched:

  - A string starting with 'y'
  - A string starting with 'Y'
  - A string starting with 't'
  - A string starting with 'T'
  - A string starting with '1'

  A false boolean is found if one of the following is matched:

  - A string starting with 'n'
  - A string starting with 'N'
  - A string starting with 'f'
  - A string starting with 'F'
  - A string starting with '0'

  The notfound value returned if no boolean is identified, does not
  necessarily have to be 0 or 1.
 */
/*--------------------------------------------------------------------------*/
int iniparser_getboolean(dictionary *d, const char *key, int notfound)
{
	char    *c;
	int     ret;

	c = iniparser_getstring(d, key, INI_INVALID_KEY);
	if (c == INI_INVALID_KEY)
		return notfound;
	if (c[0] == 'y' || c[0] == 'Y' || c[0] == '1' || c[0] == 't' || c[0] == 'T') {
		ret = 1;
	} else if (c[0] == 'n' || c[0] == 'N' || c[0] == '0' || c[0] == 'f' || c[0] == 'F') {
		ret = 0;
	} else {
		ret = notfound;
	}
	return ret;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Finds out if a given entry exists in a dictionary
  @param    ini     Dictionary to search
  @param    entry   Name of the entry to look for
  @return   integer 1 if entry exists, 0 otherwise

  Finds out if a given entry exists in the dictionary. Since sections
  are stored as keys with NULL associated values, this is the only way
  of querying for the presence of sections in a dictionary.
 */
/*--------------------------------------------------------------------------*/
int iniparser_find_entry(dictionary  *ini, const char  *entry)
{
	int found = 0;
	if (iniparser_getstring(ini, entry, INI_INVALID_KEY) != INI_INVALID_KEY) {
		found = 1;
	}
	return found;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Set an entry in a dictionary.
  @param    ini     Dictionary to modify.
  @param    entry   Entry to modify (entry name)
  @param    val     New value to associate to the entry.
  @return   int 0 if Ok, -1 otherwise.

  If the given entry can be found in the dictionary, it is modified to
  contain the provided value. If it cannot be found, -1 is returned.
  It is Ok to set val to NULL.
 */
/*--------------------------------------------------------------------------*/
int iniparser_set(dictionary *ini, const char *entry, const char *val)
{
	int result = 0;
	char *lc_entry = aw_strdup(entry);
	//strlwc(lc_entry);
	result = dictionary_set(ini, lc_entry, val);
	free(lc_entry);
	return result;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Delete an entry in a dictionary
  @param    ini     Dictionary to modify
  @param    entry   Entry to delete (entry name)
  @return   void

  If the given entry can be found, it is deleted from the dictionary.
 */
/*--------------------------------------------------------------------------*/
void iniparser_unset(dictionary *ini, const char *entry)
{
	char *lc_entry = aw_strdup(entry);
	//strlwc(lc_entry);
	dictionary_unset(ini, lc_entry);
	free(lc_entry);
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Load a single line from an INI file
  @param    input_line  Input line, may be concatenated multi-line input
  @param    section     Output space to store section
  @param    key         Output space to store key
  @param    value       Output space to store value
  @return   line_status value
 */
/*--------------------------------------------------------------------------*/
static line_status iniparser_line(int line_size, const char *input_line,
				   char **section_out, char **key_out,
				   char **value_out)
{
	line_status sta;
	int len = line_size - 1;
	char *line = malloc(line_size);
	char *key = NULL;
	char *value = NULL;
	char *equals = NULL;
	if (!line) {
		fprintf(stderr, "iniparser: memory alloc error\n");
		return LINE_ERROR;
	}

	*line = 0;
	strcpy(line, input_line);
	strstrip(line);
	len = (int)strlen(line);

	/* only allocate necessary space for key & val */
	equals = strchr(line, '=');
	if (equals) {
		value = malloc((len + line) - equals + 1);
		key = malloc(equals - line + 1);
		*value = 0;
	} else {
		key = malloc(line_size + 1);
	}

	if (!key || (equals && !value)) {
		fprintf(stderr, "iniparser: memory alloc error\n");
		sta = LINE_ERROR;
		goto out;
	}

	*key = 0;

	sta = LINE_UNPROCESSED;
	if (len < 1) {
		/* Empty line */
		sta = LINE_EMPTY;
	} else if (line[0] == '#' || line[0] == ';') {
		/* Comment line */
		sta = LINE_COMMENT;
	} else if (line[0] == '[' && line[len-1] == ']') {
		/* Section name */
		sscanf(line, "[%[^]]", key);
		strstrip(key);
		//strlwc(key);
		sta = LINE_SECTION;
		*section_out = key;

		/* don't free key's memory */
		key = NULL;
	} else if (equals && (sscanf(line, "%[^=] = %[^\n]", key, value) == 2
			||  sscanf(line, "%[^=] = '%[^\']'", key, value) == 2
			||  sscanf(line, "%[^=] = %[^;#]",   key, value) == 2)) {

		/* Usual key=value, with or without comments */
		strstrip(key);
		//strlwc(key);
		strstrip(value);
		/*
		* sscanf cannot handle '' or "" as empty values
		* this is done here
		*/
		if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
			value[0] = 0;
		}
		*key_out = key;
		*value_out = value;
		key = NULL;
		value = NULL;
		sta = LINE_VALUE;
	} else if (equals && (sscanf(line, "%[^=] = %[;#]", key, value) == 2
		||  sscanf(line, "%[^=] %[=]", key, value) == 2)) {

		/*
		* Special cases:
		* key=
		* key=;
		* key=#
		*/
		strstrip(key);
		//strlwc(key);
		value[0] = 0;
		*key_out = key;
		*value_out = value;

		/* don't free out params key or val's memory */
		key = NULL;
		value = NULL;
		sta = LINE_VALUE;
	} else {

		/* Generate syntax error */
		sta = LINE_ERROR;
	}
out:
	if (line) {
		free(line);
		line = NULL;
	}
	if (key) {
		free(key);
		key = NULL;
	}
	if (value) {
		free(value);
		value = NULL;
	}

	return sta;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Parse an ini file and return an allocated dictionary object
  @param    ininame Name of the ini file to read.
  @return   Pointer to newly allocated dictionary

  This is the parser for ini files. This function is called, providing
  the name of the file to be read. It returns a dictionary object that
  should not be accessed directly, but through accessor functions
  instead.

  The returned dictionary must be freed using iniparser_freedict().
 */
/*--------------------------------------------------------------------------*/
dictionary *iniparser_load(const char *ininame)
{
	FILE *in = NULL;

	char line[ASCIILINESZ+1];
	char *section = aw_strdup("");
	char *current_section = NULL;
	char *key = NULL;
	char *val = NULL;
	char *full_line = NULL;
	char *prev_line = NULL;

	int  len;
	int  lineno = 0;
	int  errs = 0;
	int  seckey_size = 0;

	dictionary *dict = NULL;
	in = fopen(ininame, "r");
	if (in == NULL) {
		fprintf(stderr, "iniparser: cannot open %s\n", ininame);
		goto out;
	}

	dict = dictionary_new(DICT_STORAGE_SIZE);
	if (!dict) {
		goto out;
	}

	memset(line, 0, ASCIILINESZ);

	while (fgets(line, ASCIILINESZ, in) != NULL) {
		int prev_line_len = 0;
		int multi_line = 0;
		int total_size = 0;

		if (key) {
			free(key);
			key = NULL;
		}
		if (val) {
			free(val);
			val = NULL;
		}
		lineno++;
		len = (int)strlen(line) - 1;
		if (len == 0)
			continue;
		/* Safety check against buffer overflows */
		if (line[len] != '\n' && !feof(in)) {
			fprintf(stderr,
					"iniparser: input line too long in %s (%d)\n",
					ininame,
					lineno);
			errs++;
			goto out;
		}
		/* Get rid of \n and spaces at end of line */
		while ((len >= 0) && ((line[len] == '\n') || (isspace(line[len])))) {
			line[len] = 0;
			len--;
		}

		if (len < 0) { /* Line was entirely \n and/or spaces */
			len = 0;
		}

		/* Detect multi-line */
		if (line[len] == '\\') {
			multi_line = 1;
		}
		if (multi_line) {
			/* Multi-line value */
			/* length without trailing '\' */
			/* remove multi-line indicator before appending*/
			line[len] = 0;
			len--;
		}

		/*
		 * If processing a multi-line then append it the previous portion,
		 * at this point 'full_line' has the previously read portion of a
		 * multi-line line (or NULL)
		 */
		prev_line = full_line;
		prev_line_len = 0;
		if (prev_line) {
			prev_line_len = strlen(prev_line);
		}

		/* len is not strlen(line) but strlen(line) -1 */
		total_size = (len + 1) + prev_line_len + 1;

		full_line = malloc(total_size);
		if (!full_line) {
			fprintf(stderr,
					"iniparser: out of mem\n");
			errs++;
			goto out;
		}

		memset(full_line, 0, total_size);

		if (prev_line) {
			strcpy(full_line, prev_line);
		}

		strcpy(full_line + prev_line_len, line);
		free(prev_line);
		prev_line = NULL;

		if (multi_line) {
			continue;
		}

		switch (iniparser_line(total_size, full_line, &current_section, &key, &val)) {
		case LINE_EMPTY:
		case LINE_COMMENT:
			break;
		case LINE_SECTION:
			if (section) {
				free(section);
				section = NULL;
			}
			errs = dictionary_set(dict, current_section, NULL);
			section = current_section;
			break;
		case LINE_VALUE:
			{
				char *seckey;
				/* section + ':' + key + eos */
				seckey_size = strlen(section) + strlen(key) + 2;
				seckey = malloc(seckey_size);
				if (!seckey) {
					errs++;
					fprintf(stderr, "iniparser: out of mem\n");
					goto out;
				}
				snprintf(seckey, seckey_size, "%s:%s", section, key);
				errs = dictionary_set(dict, seckey, val);
				free(seckey);
				seckey = NULL;
			}
			break;
		case LINE_ERROR:
			fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
					ininame,lineno);
			fprintf(stderr, "-> %s\n", full_line);
			errs++;
			break;
		default:
			break;
		}
		memset(line, 0, ASCIILINESZ);
		if (full_line) {
			free(full_line);
			full_line = NULL;
		}
		if (errs < 0) {
			fprintf(stderr, "iniparser: memory allocation failure\n");
			break;
		}
	}
out:
	if (errs) {
		dictionary_del(dict);
		dict = NULL;
	}
	if (val) {
		free(val);
		val = NULL;
	}
	if (key) {
		free(key);
		key = NULL;
	}
	if (section) {
		free(section);
		section = NULL;
	}
	if (full_line) {
		free(full_line);
		full_line = NULL;
	}
	if (prev_line) {
		free(prev_line);
		prev_line = NULL;
	}
	if (in) {
		fclose(in);
	}
	return dict;
}

/*-------------------------------------------------------------------------*/
/**
  @brief    Free all memory associated to an ini dictionary
  @param    d Dictionary to free
  @return   void

  Free all memory associated to an ini dictionary.
  It is mandatory to call this function before the dictionary object
  gets out of the current context.
 */
/*--------------------------------------------------------------------------*/
void iniparser_freedict(dictionary *d)
{
	dictionary_del(d);
}

int  iniparser_get_str2int(char *saddr, int value[])
{

	char  *src;
	char   off, ch;
	unsigned int  tmp_value = 0;
	int    data_count, i;
	char   tmp_str[128];
	int    sign = 1;

	data_count = 2;
	src = saddr;
	off = 0;

	if (!strncmp(src, "port:", 5)) {
		if ((src[5] == 'P') || (src[5] == 'p')) {
			off = 3;
			src += 6;
		}
	} else if (!strncmp(src, "string:", 7)) {
		off =  0;
		src += 7;
	} else if (src[0] == '"') {
		off =  5;
		src += 1;
	} else if ((src[0] == '0') && ((src[1] == 'x') || (src[1] == 'X'))) {
		src += 2;
		off  = 2;
	} else if ((src[0] >= '0') && (src[0] <= '9')) {
		off =  1;
	} else if (((src[1] >= '0') && (src[1] <= '9')) && (src[0] == '-')) {
		src++;
		off =  1;
		sign = -1;
	} else if (src[0] == '\0') {
		src++;
		off = 4;
	}

	if (off == 0) {
		data_count = 0;
		while (src[data_count] != '\0') {
			data_count++;
			if (data_count > DICT_STORAGE_SIZE - 1) {
				break;
			}
		}
		if (data_count & 0x03) {
			data_count = (data_count & (~0x03)) + 4;
		} else {
			data_count = data_count + 4;
		}
		value[0] = data_count>>2;
		if (saddr != src) {
			value[1] = 0;
		} else {
			value[1] = 1;
		}
		return DATA_TYPE_STRING;

	} else if (off == 5) {
		data_count = 0;
		while (src[data_count] != '"') {
			data_count++;
			if (data_count > DICT_STORAGE_SIZE - 1) {
				break;
			}
		}
		src[data_count] = '\0';
		if (data_count & 0x03) {
			data_count = (data_count & (~0x03)) + 4;
		} else {
			data_count = data_count + 4;
		}
		value[0] = data_count>>2;
		value[1] = 5;

		return DATA_TYPE_STRING;
	} else if (off == 1) {
		while (*src != '\0') {
			if ((*src >= '0') && (*src <= '9')) {
				tmp_value = tmp_value * 10 + (*src - '0');
				src++;
			} else {
				return -1;
			}
		}
		value[0] = tmp_value * sign;
		return DATA_TYPE_SINGLE_WORD_DEC;
	} else if (off == 2) {
		while (*src != '\0') {
			if ((*src >= '0') && (*src <= '9')) {
				tmp_value = tmp_value * 16 + (*src - '0');
				src++;
			} else if ((*src >= 'A') && (*src <= 'F')) {
				tmp_value = tmp_value * 16 + (*src - 'A' + 10);
				src++;
			} else if ((*src >= 'a') && (*src <= 'f')) {
				tmp_value = tmp_value * 16 + (*src - 'a' + 10);
				src++;
			} else {
				return -1;
			}
		}
		value[0] = tmp_value;
		return DATA_TYPE_SINGLE_WORD_HEX;
	} else if (off == 3) {

		int  tmp_flag = 0;
		ch = *src++;
		if ((ch == 'o') || (ch == 'O')) {
			ch = src[0];
			if ((ch == 'w') || (ch == 'W')) {
				ch = src[1];
				if ((ch == 'e') || (ch == 'E')) {
					ch = src[2];
					if ((ch == 'r') || (ch == 'R')) {
						value[0] = 0xffff;
						src += 3;
						tmp_flag = 1;
					}
				}
			}
		}
		if (!tmp_flag) {
			if ((ch >= 'A') && (ch <= 'Z')) {
				value[0] = ch - 'A' + 1;
			} else if ((ch >= 'a') && (ch <= 'z')) {
				value[0] = ch - 'a' + 1;
			} else {
				return -1;
			}
		}

		ch = *src++;
		tmp_value = 0;
		while (ch != '<') {
			if ((ch >= '0') && (ch <= '9')) {
				tmp_value = tmp_value * 10 + (ch - '0');
				ch = *src++;
			} else if (ch == 0) {
				src--;
				break;
			} else {
				return -1;
			}
		}
		value[1] = tmp_value;
		ch = *src++;
		while (ch != '\0') {
			i = 0;
			memset(tmp_str, 0, sizeof(tmp_str));
			while(ch != '>'){
				if((ch >= 'A') && (ch <= 'Z')){
					ch += 'a' - 'A';
				}
				tmp_str[i++] = ch;
				ch = *src++;
			}
			tmp_str[i] = '\0';
			if (!strcmp(tmp_str, "default")) {
				value[data_count] = -1;
			} else if (!strcmp(tmp_str, "none")) {
				value[data_count] = -1;
			} else if (!strcmp(tmp_str, "null")) {
				value[data_count] = -1;
			} else if (!strcmp(tmp_str, "-1")) {
				value[data_count] = -1;
			} else {
				i = 0;
				ch = tmp_str[i++];
				tmp_value = 0;
				if (ch == '-') {
					sign = -1;
					ch = tmp_str[i++];
				}
				while (ch != '\0') {
					if ((ch >= '0') && (ch <= '9'))	{
						tmp_value = tmp_value * 10 + (ch - '0');
					} else {
						return -1;
					}
					ch = tmp_str[i++];
				}
				value[data_count] = tmp_value * sign;
			}

			data_count ++;
			ch = *src++;
			if (ch == '<') {
				ch = *src++;
			} else if (ch == '\0') {
				;
			} else {
				return -1;
			}
		}
		switch (data_count) {
		case 3:
			value[3] = -1;
		case 4:
			value[4] = -1;
		case 5:
			value[5] = -1;
		case 6:
			break;
		default:
			return -1;
		}
		return DATA_TYPE_GPIO;
	} else if (off == 4) {
		value[0] = 4 >> 2;
		return DATA_EMPTY;
	} else {
		return -1;
	}
}

/* vim: set ts=4 et sw=4 tw=75 */
